package ru.incoremedia.gwttest.application.server.servlet;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;
import com.google.appengine.api.users.UserServiceFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import ru.incoremedia.gaeutils.dao.DatastoreResourceDao;
import ru.incoremedia.gwttest.application.server.dao.UserInfoDao;
import ru.incoremedia.gaeutils.model.DatastoreResource;
import ru.incoremedia.gwttest.application.server.model.UserInfo;
import ru.incoremedia.gwttest.core.client.component.FileUploader;
import ru.incoremedia.gwttest.core.client.security.UserRole;
import ru.incoremedia.gwttest.core.server.context.RequestContext;

public class AvatarUploadServlet extends HttpServlet {

    final Logger logger = Logger.getLogger(this.getClass().getName());

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html");

        try {
            if(RequestContext.getInstance().getUserRole().equals(UserRole.ROLE_GUEST)) {//если юзер разлогинился
                throw new ru.incoremedia.gwttest.core.client.exception.SecurityException();
            }

            Key avatarKey = null;

            if(ServletFileUpload.isMultipartContent(request)) {
                ServletFileUpload upload = new ServletFileUpload();

                upload.setSizeMax(524288);//512K
                FileItemIterator iter = upload.getItemIterator(request);

                while (iter.hasNext()) {
                    FileItemStream item = iter.next();

                    if (!item.isFormField()) {
                        InputStream inputStream = item.openStream();

                        try {
                            final DatastoreResourceDao datastoreResourceDao = new DatastoreResourceDao();
                            final UserInfoDao userInfoDao = new UserInfoDao();

                            UserInfo userInfo = userInfoDao.get(UserServiceFactory.getUserService().getCurrentUser().getUserId());
                            avatarKey = (Key)userInfo.getProperty(UserInfo.Property.AVATAR_KEY);

                            DatastoreResource datastoreResource = new DatastoreResource();

                            if(avatarKey != null) {
                                datastoreResource = datastoreResourceDao.get(avatarKey.getId());
                            }

                            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                            Streams.copy(inputStream, outputStream, true);

                            byte[] data;

                            try {
                                data = transformImage(outputStream.toByteArray());
                            } catch(Exception e) {
                                response.getWriter().write(FileUploader.UPLOAD_STATUS.FILE_FORMAT_EXCEPTION.toString());
                                return;
                            }

                            datastoreResource.setProperty(DatastoreResource.Property.DATA, new Blob(data));
                            avatarKey = datastoreResourceDao.saveOrUpdate(datastoreResource);
                            userInfo.setProperty(UserInfo.Property.AVATAR_KEY, avatarKey);
                            userInfoDao.saveOrUpdate(userInfo);

                            break;
                        } finally {
                            inputStream.close();
                        }
                    }
                }
            }
                        
            response.getWriter().write(FileUploader.UPLOAD_STATUS.OK.toString() + " " + avatarKey.getId());            
        } catch(ru.incoremedia.gwttest.core.client.exception.SecurityException e) {            
            response.getWriter().write(FileUploader.UPLOAD_STATUS.SECURITY_EXCEPTION.toString());
        } catch(SizeLimitExceededException e) {
            response.getWriter().write(FileUploader.UPLOAD_STATUS.SIZE_LIMIT_EXCEPTION.toString());        
        } catch (Exception e) {
            response.getWriter().write(FileUploader.UPLOAD_STATUS.UNKNOWN_EXCEPTION.toString());
            logger.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    private byte[] transformImage(byte[] data) {
        ImagesService imagesService = ImagesServiceFactory.getImagesService();

        Image image = ImagesServiceFactory.makeImage(data);

        int height = image.getHeight();
        int width  = image.getWidth();

        Transform transform;

        if(width > height) {
            double cropSize = (width - height) / ((double)2 * width);
            transform = ImagesServiceFactory.makeCrop(cropSize, 0, 1 - cropSize, 1);
        } else {
            double cropSize = (height - width) / ((double)2 * height);
            transform = ImagesServiceFactory.makeCrop(0, cropSize, 1, 1 - cropSize);
        }

        image = imagesService.applyTransform(transform, image);

        transform = ImagesServiceFactory.makeResize(128, 128);
        return imagesService.applyTransform(transform, image).getImageData();
    }
}
